package ling.common;

import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.api.proxy.entity.select.EntityQueryable;
import com.easy.query.api4j.client.DefaultEasyQuery;
import com.easy.query.api4j.client.EasyQuery;
import com.easy.query.api4j.select.Queryable;
import com.easy.query.core.api.client.EasyQueryClient;
import com.easy.query.core.basic.jdbc.tx.Transaction;

import com.easy.query.core.proxy.ProxyEntity;
import com.easy.query.core.proxy.ProxyEntityAvailable;
import lombok.var;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.sql.DataSource;

import java.util.*;

/** 数据查询管理
 * @Author :He-LiangLiang@Outlook.com
 * @date : 2024/3/8
 * @description: from jd
 */
@Component
public class EQueryHelper {
    @Resource
    DataSource dataSource;
    //static EasyQueryClient client;
    @Resource
    private EasyEntityQuery easyEntityQuery;
    @Resource
    EasyQueryClient client;
    EasyQuery query;

    public EasyEntityQuery entityQuery(){
        return easyEntityQuery;
    }
    public <TProxy extends ProxyEntity<TProxy, T>, T extends ProxyEntityAvailable<T, TProxy>> EntityQueryable<TProxy, T> entityQuery(Class<T> var1){
        return easyEntityQuery.queryable(var1);
    }
    public <T> Queryable<T> queryable(Class<T> var1) {
        return new DefaultEasyQuery(queryClient()).queryable(var1);
    }
    public EasyQuery query() {
        if (query == null)
            query = new DefaultEasyQuery(queryClient());

        return query;
    }
    public EasyQueryClient queryClient() {
//        if (client == null) {
//            LogFactory.useStdOutLogging();
//            client = EasyQueryBootstrapper.defaultBuilderConfiguration()
//                    .setDefaultDataSource(dataSource)
//                    .optionConfigure(op -> {
//                        op.setPrintSql(true);
//                    })
//                    .useDatabaseConfigure(new MySQLDatabaseConfiguration())
//                    .build();
//            client.getRuntimeContext().getQueryConfiguration().applyInterceptor(new DeptInterceptor());
//        }
        return client;
    }
    public List<Map<String, Object>> sqlQueryMap(Map.Entry<String, List<Object>> pl) {
        return queryClient().sqlQueryMap(pl.getKey(), pl.getValue());
    }

    public SqlItemsByEQ CreateItems(String itemSql, Object... paramVal) {
        return new SqlItemsByEQ(queryClient(), itemSql, paramVal);
    }

    public String clearComments(String sql) {
        sql = sql.replaceAll("--[^'\\r\\n]*[\\r\\n]{1}", " ");
        // sql = sql.replaceAll("/\\*.*?\\*/", " ");
        return sql;
    }

    /**
     * sql简单拼接帮助
     *
     * @Author :He-LiangLiang@Outlook.com
     * @date : 2024/3/8
     * @description: 不依赖 mybatis.new SQL()
     */
    public interface ISqlPart {
        public void append(StringBuilder stb, List<Object> list);

        public default Map.Entry<String, List<Object>> buildTo() {
            StringBuilder stb = new StringBuilder();
            List<Object> list = new ArrayList<>();
            append(stb, list);
            return new AbstractMap.SimpleEntry<>(stb.toString(), list);
        }
    }

    public static class SqlPart implements ISqlPart {

        String sqlStr;
        Object[] sqlParams;

        SqlPart(String partSql, Object... param) {
            sqlStr = partSql;
            sqlParams = param;
        }

        //@Override
        public void append(StringBuilder stb, List<Object> list) {
            stb.append(sqlStr);
            if (sqlParams == null || sqlParams.length == 0)
                return;
            list.addAll(Arrays.asList(sqlParams));
        }


    }

    public static class SqlItems implements ISqlPart {
        List<ISqlPart> partList;

        private SqlItems(String itemSql, Object[] param) {
            partList = new ArrayList<>();
            addItem(itemSql, param);
        }

        public static SqlItems AddItem(String itemSql, Object... param) {
            SqlItems list = new SqlItems(itemSql, param);
            return list;
        }

        public SqlItems addItem(String itemSql, Object... param) {

            partList.add(new SqlPart(itemSql, param));
            return this;
        }

        public SqlItems addItem(ISqlPart part) {

            partList.add(part);
            return this;
        }

        public SqlItems and(String itemSql, Object... paramVal) {
            if (itemSql == null)
                return this;
            addItem(" and " + itemSql, paramVal);
            return this;
        }
        public SqlItems and() {
            return  and(" ");
        }
        public SqlItems in(String inName, Object... paramVal) {
            if (inName == null)
                return this;
            var itemStr=String.join(",",Arrays.stream(paramVal).map(p->"?").toArray(String[]::new));
            var sql=String.format(" %s in (%s) ",inName,itemStr);
            addItem(sql, paramVal);
            return this;
        }


        public SqlItems andNotNull(String itemSql, Object... paramVal) {
            if (paramVal == null || paramVal.length < 1)
                return and(itemSql, paramVal);
            var paramVal1 = paramVal[0];
            if (paramVal1 == null) return this;
            if (paramVal1 instanceof String && !StringUtils.hasText(paramVal1.toString()))
                return this;
            return and(itemSql, paramVal);
        }

        @Override
        public void append(StringBuilder stb, List<Object> list) {
            if (partList == null || partList.size() < 1)
                return;
            for (ISqlPart item : partList) {
                if (item instanceof SqlItems) {
                    SqlItems tmp = (SqlItems) item;
                    if (tmp.partList != null && tmp.partList.size() > 0) {
                        stb.append(" ( ");
                        item.append(stb, list);
                        stb.append(" ) ");
                    }
                } else
                    item.append(stb, list);
            }
        }

        public SqlItems groupBy(String sql) {
            if (!StringUtils.hasText(sql))
                return this;
            partList.add(new SqlPart(" group by " + sql, null));
            return this;
        }

        public SqlResultByEQ page(int number, int size) {
            int begin = (number - 1) * size;
            var stb = new StringBuilder();
            List<Object> list = new ArrayList<>();
            stb.append("select * from ( ");
            append(stb, list);
            stb.append(" ) page_tab_1 limit " + begin + "," + size);
            return resultPkg(stb.toString(), list);
        }
        public SqlItems limit(int number, int size) {
            int begin = (number - 1) * size;
            partList.add(new SqlPart(String.format(" limit %s,%s ", begin, size), null));
            return this;
        }

        public SqlResultByEQ count() {
            var stb = new StringBuilder();
            List<Object> list = new ArrayList<>();
            stb.append(" select count(1) `count` from ( ");
            append(stb, list);
            stb.append(" ) count_tab_1");
            return resultPkg(stb.toString(), list);
        }
        public  SqlResultByEQ resultPkg( ){
            var re=buildTo();
            return resultPkg(re.getKey(),re.getValue());
        }
        SqlResultByEQ resultPkg(String sql, List<Object> param) {
            return new SqlResultByEQ(sql, param);
        }
    }

    /**
     * sql简单拼接帮助,easy-query扩展
     *
     * @Author :He-LiangLiang@Outlook.com
     * @date : 2024/3/8
     * @description:
     */
    public static class SqlResultByEQ extends AbstractMap.SimpleEntry<String, List<Object>> {

        EasyQueryClient query;

        public SqlResultByEQ setQueryClient(EasyQueryClient client) {
            query = client;
            return this;
        }

        public SqlResultByEQ(String key, List<Object> value) {
            super(key, value);
        }

        public <T> List<T> sqlQuery(Class<T> clazz) {
            return query.sqlQuery(getKey(), clazz, getValue());
        }
        public <T> List<T> sqlQuery(Class<T> clazz, Isolation transactionLevel) {//
            if (transactionLevel == null)
                transactionLevel = Isolation.READ_UNCOMMITTED; //Connection.TRANSACTION_READ_UNCOMMITTED
            try (Transaction transaction = query.beginTransaction(transactionLevel.value())) {
                return query.sqlQuery(getKey(), clazz, getValue());
            }
        }

        public List<Map<String, Object>> queryMap() {
            return query.sqlQueryMap(getKey(), getValue());
        }

        public Object querySingle(String colName) {
            return query.sqlQueryMap(getKey(), getValue()).get(0).get(colName);
        }

        public Long query2Count() {
            return (Long) querySingle("count");
        }
    }

    public static class SqlItemsByEQ extends SqlItems {
        EasyQueryClient query;

        public SqlItemsByEQ(EasyQueryClient client, String sql, Object[] sqlparams) {
            super(sql, sqlparams);
            query = client;
        }


        @Override
        SqlResultByEQ resultPkg(String sql, List<Object> param) {
            return super.resultPkg(sql, param).setQueryClient(query);
        }
    }

}
